import React, { useRef, useState } from 'react';
import { Card, Button, Input, Select, Switch, DatePicker, Divider, Table, Space, message } from 'antd';
import { 
  BgColorsOutlined, 
  FormOutlined, 
  TableOutlined, 
  PictureOutlined,
  ContainerOutlined,
  BarChartOutlined,
  FileTextOutlined
} from '@ant-design/icons';
import { useApp } from '../../context/AppContext.jsx'; // 注意路径可能需要调整，假设是在components/designer目录下
import { DndContext, closestCenter, useDroppable, useDraggable } from '@dnd-kit/core';
import { SortableContext, verticalListSortingStrategy, arrayMove, useSortable } from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';

// 辅助函数：根据路径获取组件的唯一ID
const getComponentIdByPath = (components, path) => {
  const component = findComponentByPath(components, path);
  return component ? component.id : null;
};

// 辅助函数：根据路径查找组件 (从DesignerPage复制过来，确保Canvas内部也能用)
const findComponentByPath = (components, path) => {
  let current = components;
  let component = null;
  for (let i = 0; i < path.length; i++) {
    const index = path[i];
    if (!current || index === undefined || index >= current.length) {
      return null; // 路径无效
    }
    component = current[index];
    if (i < path.length - 1) {
      current = component.children;
    }
  }
  return component;
};

// 辅助函数：根据路径更新组件属性 (从DesignerPage复制过来，确保Canvas内部也能用)
const updateComponentByPath = (components, path, updatedProps) => {
  if (!path || path.length === 0) return components; // 根组件或无效路径

  const newComponents = JSON.parse(JSON.stringify(components)); // Deep copy to ensure immutability
  let current = newComponents;

  for (let i = 0; i < path.length; i++) {
    const index = path[i];
    if (index === undefined || index >= current.length) {
      return components; // 路径无效
    }

    if (i === path.length - 1) {
      // 找到目标组件，更新其属性
      current[index] = { ...current[index], ...updatedProps };
    } else {
      // 遍历到父级，确保children是新的数组以保持不变性
      current[index] = { ...current[index], children: [...(current[index].children || [])] };
      current = current[index].children;
    }
  }
  return newComponents;
};

// 工具函数：根据组件类型渲染内容
function renderComponent(component, isSelected, preview) {
  const { type, props } = component;
  switch (type) {
    case 'text':
      return (
        <div style={{ fontSize: props.fontSize || 14, color: props.color || '#333' }}>
          {props.content || '文本内容'}
        </div>
      );
    case 'image':
      return (
        <img
          src={props.src || 'https://via.placeholder.com/200x150'}
          alt={props.alt || '图片'}
          style={{
            width: props.width || 200,
            height: props.height || 150,
            objectFit: 'cover',
            borderRadius: 4
          }}
        />
      );
    case 'button':
      return (
        <Button
          type={props.type || 'primary'}
          size={props.size || 'middle'}
          style={{ borderRadius: 6 }}
        >
          {props.text || '按钮'}
        </Button>
      );
    case 'divider':
      return null; // 已在 AbsoluteComponentRenderer 里特殊处理
    case 'input':
      return (
        <Input
          placeholder={props.placeholder || '请输入'}
          type={props.inputType || 'text'}
          style={{ borderRadius: 6 }}
        />
      );
    case 'textarea':
      return (
        <Input.TextArea
          placeholder={props.placeholder || '请输入'}
          rows={props.rows || 4}
          style={{ borderRadius: 6 }}
        />
      );
    case 'select':
      return (
        <Select
          placeholder={props.placeholder || '请选择'}
          style={{ width: '100%', borderRadius: 6 }}
          options={props.options || [
            { value: 'option1', label: '选项1' },
            { value: 'option2', label: '选项2' }
          ]}
        />
      );
    case 'checkbox':
      return (
        <Space>
          <Switch checked={props.checked || false} />
          <span>{props.text || '复选框'}</span>
        </Space>
      );
    case 'radio':
      return (
        <Space>
          <Switch checked={props.checked || false} />
          <span>{props.text || '单选框'}</span>
        </Space>
      );
    case 'switch':
      return <Switch checked={props.checked || false} />;
    case 'datepicker':
      return (
        <DatePicker
          placeholder={props.placeholder || '请选择日期'}
          style={{ width: '100%', borderRadius: 6 }}
          format={props.format || 'YYYY-MM-DD'}
        />
      );
    case 'table':
      return (
        <Table
          columns={props.columns || [
            { title: '姓名', dataIndex: 'name' },
            { title: '年龄', dataIndex: 'age' }
          ]}
          dataSource={(props.dataSource || [
            { name: '张三', age: 25 },
            { name: '李四', age: 30 }
          ]).map((row, i) => ({ ...row, key: (row.id ? String(row.id) : '') + '_' + i }))}
          pagination={false}
          size="small"
        />
      );
    case 'chart':
      return (
        <div style={{
          width: 400,
          height: 300,
          border: '1px solid #e5e6eb',
          borderRadius: 6,
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          background: '#fafafa'
        }}>
          <div style={{ color: '#999' }}>
            <BarChartOutlined style={{ fontSize: 48, marginBottom: 16 }} />
            <div>图表组件</div>
          </div>
        </div>
      );
    default:
      return <div>未知组件类型: {type}</div>;
  }
}

// 工具函数：浅比较两个数组内容是否相等
function shallowEqualArr(arr1, arr2) {
  if (arr1.length !== arr2.length) return false;
  for (let i = 0; i < arr1.length; i++) {
    if (arr1[i].type !== arr2[i].type || arr1[i].x !== arr2[i].x || arr1[i].y !== arr2[i].y) return false;
  }
  return true;
}

// 组件渲染器
// 接受 path prop 来追踪组件在树中的位置
const ComponentRenderer = ({ component, isSelected, onClick, preview = false, id, path, onSelect, onComponentDragEnd }) => {
  const { type, props, style } = component;

  const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id: id });

  const styleTransform = {
    transform: CSS.Transform.toString(transform),
    transition,
  };

  // 新增：用于容器组件的 droppable 功能
  const isContainer = ['container', 'row', 'col'].includes(type);
  const { setNodeRef: setDroppableNodeRef, isOver } = useDroppable({
    id: `droppable-${id}`, // 唯一ID，区分于sortableId
    data: {
      isContainer: true,
      componentId: id,
      path: path,
    }
  });

  const handleClick = (e) => {
    if (!preview) {
      e.stopPropagation();
      console.log('clicked path', path); // 调试输出
      onClick(path); // 传递当前组件的完整路径
    }
  };

  const containerStyle = {
    ...style,
    border: isSelected ? '2px solid #1890ff' : (isOver && isContainer ? '2px dashed #1890ff' : '1px solid #e5e6eb'), // 拖拽到上方时显示虚线边框
    borderRadius: 8,
    padding: 8,
    margin: 4,
    cursor: preview ? 'default' : 'pointer',
    position: 'relative',
    transition: 'all 0.2s',
    background: isSelected ? '#e6f7ff' : (isOver && isContainer ? '#f0f8ff' : '#fff'), // 拖拽到上方时背景变浅
    ...styleTransform, // 应用dnd-kit的transform
  };

  // 渲染不同类型的组件
  const renderComponent = () => {
    switch (type) {
      case 'text':
        return (
          <div style={{ fontSize: props.fontSize || 14, color: props.color || '#333' }}>
            {props.content || '文本内容'}
          </div>
        );
      
      case 'image':
        return (
          <img 
            src={props.src || 'https://via.placeholder.com/200x150'} 
            alt={props.alt || '图片'}
            style={{ 
              width: props.width || 200, 
              height: props.height || 150,
              objectFit: 'cover',
              borderRadius: 4
            }}
          />
        );
      
      case 'button':
        return (
          <Button 
            type={props.type || 'primary'}
            size={props.size || 'middle'}
            style={{ borderRadius: 6 }}
          >
            {props.text || '按钮'}
          </Button>
        );
      
      case 'divider':
        return (
          <div
            style={{
              minHeight: 32,
              width: '100%',
              display: 'flex',
              alignItems: 'center',
              cursor: preview ? 'default' : 'pointer',
              pointerEvents: 'auto',
              background: isSelected ? 'rgba(24,144,255,0.08)' : undefined,
            }}
          >
            <Divider type={props.type || 'horizontal'} style={{ width: '100%', margin: 0 }} />
          </div>
        );
      
      case 'input':
        return (
          <Input 
            placeholder={props.placeholder || '请输入'}
            type={props.inputType || 'text'}
            style={{ borderRadius: 6 }}
          />
        );
      
      case 'textarea':
        return (
          <Input.TextArea 
            placeholder={props.placeholder || '请输入'}
            rows={props.rows || 4}
            style={{ borderRadius: 6 }}
          />
        );
      
      case 'select':
        return (
          <Select 
            placeholder={props.placeholder || '请选择'}
            style={{ width: '100%', borderRadius: 6 }}
            options={props.options || [
              { value: 'option1', label: '选项1' },
              { value: 'option2', label: '选项2' }
            ]}
          />
        );
      
      case 'checkbox':
        return (
          <Space>
            <Switch checked={props.checked || false} />
            <span>{props.text || '复选框'}</span>
          </Space>
        );
      
      case 'radio':
        return (
          <Space>
            <Switch checked={props.checked || false} />
            <span>{props.text || '单选框'}</span>
          </Space>
        );
      
      case 'switch':
        return <Switch checked={props.checked || false} />;
      
      case 'datepicker':
        return (
          <DatePicker 
            placeholder={props.placeholder || '请选择日期'}
            style={{ width: '100%', borderRadius: 6 }}
            format={props.format || 'YYYY-MM-DD'}
          />
        );
      
      case 'container':
        return (
          <div style={{ 
            padding: 16, 
            border: '1px dashed #d9d9d9', 
            borderRadius: 6,
            minHeight: 100,
            background: '#fafafa',
            display: 'flex',
            flexDirection: props.direction === 'horizontal' ? 'row' : 'column',
            gap: props.gap || 8,
            alignItems: 'flex-start',
            justifyContent: 'flex-start',
          }}>
            <div style={{ color: '#999', textAlign: 'center', width: '100%' }}>容器 ({props.direction || 'vertical'})</div>
            {component.children && component.children.length > 0 && (
              <Canvas 
                components={component.children}
                selectedPath={selectedPath}
                onSelect={onSelect}
                preview={preview}
                parentPath={path}
                onComponentDragEnd={onComponentDragEnd}
              />
            )}
            {(!component.children || component.children.length === 0) && !preview && (
              <div style={{ color: '#bbb', textAlign: 'center', padding: 20 }}>
                拖拽组件到此容器
              </div>
            )}
          </div>
        );
      
      case 'row':
        return (
          <div style={{ 
            display: 'flex', 
            marginBottom: 16,
            padding: 8,
            border: '1px dashed #d9d9d9',
            borderRadius: 6,
            background: '#fafafa',
            gap: props.gutter || 0,
            alignItems: 'flex-start',
            justifyContent: 'flex-start',
          }}>
            <div style={{ color: '#999', textAlign: 'center', flex: 1 }}>行布局</div>
            {component.children && component.children.length > 0 && (
              <Canvas 
                components={component.children}
                selectedPath={selectedPath}
                onSelect={onSelect}
                preview={preview}
                parentPath={path}
                onComponentDragEnd={onComponentDragEnd}
              />
            )}
            {(!component.children || component.children.length === 0) && !preview && (
              <div style={{ color: '#bbb', textAlign: 'center', flex: 1, padding: 20 }}>
                拖拽组件到此行
              </div>
            )}
          </div>
        );
      
      case 'col':
        return (
          <div style={{ 
            flex: props.span ? (props.span / 24) : 1, // Antd Col span out of 24
            padding: '0 8px',
            border: '1px dashed #d9d9d9',
            borderRadius: 6,
            background: '#fafafa',
            margin: '0 4px',
            minHeight: 50,
            display: 'flex',
            flexDirection: 'column',
            alignItems: 'stretch',
            justifyContent: 'flex-start',
          }}>
            <div style={{ color: '#999', textAlign: 'center' }}>列 ({props.span || 1})</div>
            {component.children && component.children.length > 0 && (
              <Canvas 
                components={component.children}
                selectedPath={selectedPath}
                onSelect={onSelect}
                preview={preview}
                parentPath={path}
                onComponentDragEnd={onComponentDragEnd}
              />
            )}
            {(!component.children || component.children.length === 0) && !preview && (
              <div style={{ color: '#bbb', textAlign: 'center', padding: 20 }}>
                拖拽组件到此列
              </div>
            )}
          </div>
        );
      
      case 'table':
        return (
          <Table 
            columns={props.columns || [
              { title: '姓名', dataIndex: 'name' },
              { title: '年龄', dataIndex: 'age' }
            ]}
            dataSource={(props.dataSource || [
              { name: '张三', age: 25 },
              { name: '李四', age: 30 }
            ]).map((row, i) => ({ ...row, key: (row.id ? String(row.id) : '') + '_' + i }))}
            pagination={false}
            size="small"
          />
        );
      
      case 'chart':
        return (
          <div style={{ 
            width: 400, 
            height: 300, 
            border: '1px solid #e5e6eb',
            borderRadius: 6,
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            background: '#fafafa'
          }}>
            <div style={{ color: '#999' }}>
              <BarChartOutlined style={{ fontSize: 48, marginBottom: 16 }} />
              <div>图表组件</div>
            </div>
          </div>
        );
      
      default:
        return <div>未知组件类型: {type}</div>;
    }
  };

  return (
    <div style={containerStyle}>
      {/* 拖拽手柄 */}
      <div
        ref={setNodeRef}
        {...(isSelected ? { ...attributes, ...listeners } : {})}
        style={{
          position: 'absolute',
          top: 2,
          left: 2,
          width: 16,
          height: 16,
          background: '#e6f7ff',
          border: '1px solid #1890ff',
          borderRadius: 4,
          cursor: preview ? 'default' : (isSelected ? 'grab' : 'not-allowed'),
          zIndex: 10,
          display: preview ? 'none' : 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          fontSize: 12,
          userSelect: 'none',
          opacity: isSelected ? 1 : 0.5,
        }}
        title={isSelected ? "拖拽排序" : "请先选中再拖拽"}
      >
        ≡
      </div>
      {/* 内容区，点击选中 */}
      <div onClick={handleClick} style={{ width: '100%', height: '100%', pointerEvents: 'auto' }}>
        {renderComponent()}
      </div>
      {isSelected && !preview && (
        <div style={{
          position: 'absolute',
          top: -8,
          left: -8,
          background: '#1890ff',
          color: '#fff',
          borderRadius: '50%',
          width: 20,
          height: 20,
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          fontSize: 12,
          fontWeight: 'bold'
        }}>
          ✓
        </div>
      )}
      {isContainer && !preview && (
        <div
          ref={setDroppableNodeRef} // 用于接收拖拽
          style={{
            position: 'absolute',
            top: 0,
            left: 0,
            right: 0,
            bottom: 0,
            zIndex: 1,
            pointerEvents: 'none', // 不阻挡点击
          }}
        />
      )}
    </div>
  );
};

// 绝对定位拖拽渲染器
const AbsoluteComponentRenderer = ({ component, isSelected, onClick, preview = false, id, style }) => {
  if (preview) {
    // 预览模式只渲染内容
    console.log('预览渲染', component, component.style);
    const previewStyle = {
      position: 'absolute',
      left: (component.style && component.style.left !== undefined) ? component.style.left : 40,
      top: (component.style && component.style.top !== undefined) ? component.style.top : 40,
      width: (component.style && component.style.width) || 120,
      height: (component.style && component.style.height) || 40,
      background: '#fff',
      borderRadius: 8,
      ...component.style,
    };
    return (
      <div style={previewStyle}>
        {component.type === 'divider' ? (
          <div style={{ minHeight: 32, width: '100%', display: 'flex', alignItems: 'center', pointerEvents: 'auto' }}>
            <Divider type={component.props.type || 'horizontal'} style={{ width: '100%', margin: 0 }} />
          </div>
        ) : renderComponent(component, false, true)}
      </div>
    );
  }
  const { attributes, listeners, setNodeRef, transform } = useDraggable({ id });
  const absStyle = {
    position: 'absolute',
    left: style.left || 0,
    top: style.top || 0,
    width: style.width || 120,
    height: style.height || 40,
    zIndex: isSelected ? 10 : 1,
    borderRadius: 8,
    ...style,
    transform: transform ? `translate3d(${transform.x}px, ${transform.y}px, 0)` : undefined,
    transition: 'box-shadow 0.2s, border 0.2s, background 0.2s',
    cursor: preview ? 'default' : 'move',
    pointerEvents: 'auto',
  };
  return (
    <div
      ref={setNodeRef}
      className={`canvas-component${isSelected ? ' canvas-component-selected' : ''}`}
      style={absStyle}
      {...attributes}
      {...listeners}
      onMouseDown={e => {
        e.stopPropagation();
        onClick && onClick();
        console.log('mousedown', id);
      }}
    >
      {/* 左上角蓝点可保留，也可交给 CSS ::before 控制 */}
      <div style={{ width: '100%', height: '100%', pointerEvents: 'none' }}>
        {component.type === 'divider' ? (
          <div style={{ minHeight: 32, width: '100%', display: 'flex', alignItems: 'center', pointerEvents: 'none' }}>
            <Divider type={component.props.type || 'horizontal'} style={{ width: '100%', margin: 0 }} />
          </div>
        ) : renderComponent(component, isSelected, preview)}
      </div>
    </div>
  );
};

// 检测两个矩形是否重叠
function isRectOverlap(a, b) {
  return !(
    a.left + a.width <= b.left ||
    a.left >= b.left + b.width ||
    a.top + a.height <= b.top ||
    a.top >= b.top + b.height
  );
}

// 自动吸附到最近不重叠位置
function findNearestNonOverlappingPosition(comp, prev, tryLeft, tryTop, width, height, canvasRect) {
  const step = 10;
  const maxRadius = 200; // 最大查找半径
  const minLeft = 0;
  const minTop = 0;
  const maxLeft = canvasRect ? canvasRect.width - width : 1000;
  const maxTop = canvasRect ? canvasRect.height - height : 1000;

  // 先尝试当前位置
  let newRect = { left: tryLeft, top: tryTop, width, height };
  let hasCollision = prev.some(other =>
    other.id !== comp.id &&
    isRectOverlap(newRect, {
      left: other.style.left || 0,
      top: other.style.top || 0,
      width: other.style.width || 120,
      height: other.style.height || 40,
    })
  );
  if (!hasCollision &&
      tryLeft >= minLeft && tryTop >= minTop &&
      tryLeft <= maxLeft && tryTop <= maxTop) {
    return { left: tryLeft, top: tryTop };
  }

  // 螺旋查找
  for (let r = step; r <= maxRadius; r += step) {
    for (let dx = -r; dx <= r; dx += step) {
      for (let dy = -r; dy <= r; dy += step) {
        if (Math.abs(dx) !== r && Math.abs(dy) !== r) continue; // 只查边界
        const left = tryLeft + dx;
        const top = tryTop + dy;
        if (left < minLeft || top < minTop || left > maxLeft || top > maxTop) continue;
        newRect = { left, top, width, height };
        hasCollision = prev.some(other =>
          other.id !== comp.id &&
          isRectOverlap(newRect, {
            left: other.style.left || 0,
            top: other.style.top || 0,
            width: other.style.width || 120,
            height: other.style.height || 40,
          })
        );
        if (!hasCollision) {
          return { left, top };
        }
      }
    }
  }
  // 实在找不到就回到原位
  return { left: tryLeft, top: tryTop };
}

// 画布自由布局拖拽处理，带碰撞检测
function handleDragEndAbsolute(event, components, setCanvas) {
  const { active, delta } = event;
  const id = active.id;
  setCanvas(prev => {
    return prev.map(comp => {
      if (comp.id === id) {
        const left = (comp.style.left || 0) + delta.x;
        const top = (comp.style.top || 0) + delta.y;
        const width = comp.style.width || 120;
        const height = comp.style.height || 40;
        // 检查碰撞
        const newRect = { left, top, width, height };
        const hasCollision = prev.some(other =>
          other.id !== id &&
          isRectOverlap(newRect, {
            left: other.style.left || 0,
            top: other.style.top || 0,
            width: other.style.width || 120,
            height: other.style.height || 40,
          })
        );
        if (hasCollision) {
          // 有碰撞，自动吸附到最近不重叠位置
          const { left: newLeft, top: newTop } = findNearestNonOverlappingPosition(
            comp, prev, left, top, width, height
          );
          return { ...comp, style: { ...comp.style, left: newLeft, top: newTop } };
        }
        // 无碰撞，允许移动
        return { ...comp, style: { ...comp.style, left, top } };
      }
      return comp;
    });
  });
}

const SNAP_THRESHOLD = 8; // 吸附阈值

export default function Canvas({ components = [], selectedPath, onSelect, preview = false, style }) {
  const { setCanvas } = useApp();
  const [snapLines, setSnapLines] = useState([]); // 辅助线状态
  const dragInfoRef = useRef(null); // 记录拖拽中的组件信息
  const canvasRef = useRef(null); // 画布ref

  // 计算所有可吸附的边缘
  function getAllEdges(excludeId) {
    return components.filter(c => c.id !== excludeId).map(c => {
      const left = c.style.left || 0;
      const top = c.style.top || 0;
      const width = c.style.width || 120;
      const height = c.style.height || 40;
      return {
        id: c.id,
        left,
        right: left + width,
        top,
        bottom: top + height,
        centerX: left + width / 2,
        centerY: top + height / 2,
      };
    });
  }

  // 拖拽移动时，检测吸附并显示辅助线
  function handleDragMove(event) {
    const { active, delta } = event;
    const id = active.id;
    const comp = components.find(c => c.id === id);
    if (!comp) return;
    const width = Number(comp.style.width) || 120;
    const height = Number(comp.style.height) || 40;
    let left = Number(comp.style.left) || 0;
    let top = Number(comp.style.top) || 0;
    left += delta.x;
    top += delta.y;
    // 边界限制
    const canvasRect = canvasRef.current?.getBoundingClientRect();
    if (canvasRect && canvasRect.width > 0 && canvasRect.height > 0) {
      left = Math.max(0, Math.min(left, canvasRect.width - width));
      top = Math.max(0, Math.min(top, canvasRect.height - height));
    }
    const right = left + width;
    const bottom = top + height;
    const centerX = left + width / 2;
    const centerY = top + height / 2;
    const edges = getAllEdges(id);
    // 横向吸附（只吸最近的一个）
    let minDeltaX = SNAP_THRESHOLD + 1, snapLeft = left, snapVLine = null;
    [
      ...edges.map(e => ({ x: e.left, type: 'v' })),
      ...edges.map(e => ({ x: e.right, type: 'v' })),
      ...edges.map(e => ({ x: e.centerX, type: 'v' })),
      { x: 0, type: 'v' }
    ].forEach(({ x, type }) => {
      const deltas = [Math.abs(left - x), Math.abs(right - x), Math.abs(centerX - x)];
      deltas.forEach((delta, idx) => {
        if (delta < minDeltaX && delta < SNAP_THRESHOLD) {
          minDeltaX = delta;
          if (idx === 0) snapLeft = x;
          if (idx === 1) snapLeft = x - width;
          if (idx === 2) snapLeft = x - width / 2;
          snapVLine = { type, x };
        }
      });
    });
    // 纵向吸附（只吸最近的一个）
    let minDeltaY = SNAP_THRESHOLD + 1, snapTop = top, snapHLine = null;
    [
      ...edges.map(e => ({ y: e.top, type: 'h' })),
      ...edges.map(e => ({ y: e.bottom, type: 'h' })),
      ...edges.map(e => ({ y: e.centerY, type: 'h' })),
      { y: 0, type: 'h' }
    ].forEach(({ y, type }) => {
      const deltas = [Math.abs(top - y), Math.abs(bottom - y), Math.abs(centerY - y)];
      deltas.forEach((delta, idx) => {
        if (delta < minDeltaY && delta < SNAP_THRESHOLD) {
          minDeltaY = delta;
          if (idx === 0) snapTop = y;
          if (idx === 1) snapTop = y - height;
          if (idx === 2) snapTop = y - height / 2;
          snapHLine = { type, y };
        }
      });
    });
    dragInfoRef.current = { id, snapLeft, snapTop };
    const lines = [];
    if (snapVLine) lines.push({ ...snapVLine, highlight: true });
    if (snapHLine) lines.push({ ...snapHLine, highlight: true });
    setSnapLines(prev => shallowEqualArr(prev, lines) ? prev : lines);
  }

  // 拖拽结束，吸附到目标边缘或自动吸附
  function handleDragEnd(event) {
    const { active, delta } = event;
    const id = active.id;
    setCanvas(prev => {
      return prev.map(comp => {
        if (comp.id === id) {
          const left = (comp.style.left || 0) + delta.x;
          const top = (comp.style.top || 0) + delta.y;
          const width = comp.style.width || 120;
          const height = comp.style.height || 40;
          // 边界限制
          const canvasRect = canvasRef.current?.getBoundingClientRect();
          // 检查碰撞
          const newRect = { left, top, width, height };
          const hasCollision = prev.some(other =>
            other.id !== id &&
            isRectOverlap(newRect, {
              left: other.style.left || 0,
              top: other.style.top || 0,
              width: other.style.width || 120,
              height: other.style.height || 40,
            })
          );
          if (hasCollision) {
            // 有碰撞，自动吸附到最近不重叠位置
            const { left: newLeft, top: newTop } = findNearestNonOverlappingPosition(
              comp, prev, left, top, width, height, canvasRect
            );
            return { ...comp, style: { ...comp.style, left: newLeft, top: newTop } };
          }
          // 无碰撞，允许移动
          // 也要限制在画布内
          let finalLeft = left, finalTop = top;
          if (canvasRect && canvasRect.width > 0 && canvasRect.height > 0) {
            finalLeft = Math.max(0, Math.min(left, canvasRect.width - width));
            finalTop = Math.max(0, Math.min(top, canvasRect.height - height));
          }
          return { ...comp, style: { ...comp.style, left: finalLeft, top: finalTop } };
        }
        return comp;
      });
    });
    setSnapLines([]);
    dragInfoRef.current = null;
  }

  return (
    <div
      ref={canvasRef}
      className="designer-canvas"
      style={{
        width: '100%',
        height: preview ? (style?.height || 600) : '100%',
        minHeight: 0,
        minWidth: 0,
        background: preview ? '#fff' : 'linear-gradient(135deg, #e6f7ff 0%, #f5f6fa 100%)',
        borderRadius: 12,
        boxShadow: '0 4px 16px #e5e6eb',
        border: '1px solid #e5e6eb',
        position: 'relative',
        overflow: 'auto',
        ...style,
      }}
    >
      {/* 辅助线渲染 */}
      {snapLines.map((line, i) =>
        line.type === 'v' ? (
          <div key={i} style={{ position: 'absolute', left: line.x, top: 0, bottom: 0, width: 2, background: line.highlight ? '#1890ff' : '#bae0ff', zIndex: 1000, pointerEvents: 'none', boxShadow: line.highlight ? '0 0 8px #1890ff' : undefined }} />
        ) : (
          <div key={i} style={{ position: 'absolute', top: line.y, left: 0, right: 0, height: 2, background: line.highlight ? '#1890ff' : '#bae0ff', zIndex: 1000, pointerEvents: 'none', boxShadow: line.highlight ? '0 0 8px #1890ff' : undefined }} />
        )
      )}
      {preview ? (
        components.map((component, index) => (
          <AbsoluteComponentRenderer
            key={component.id}
            id={component.id}
            component={component}
            isSelected={false}
            onClick={() => {}}
            preview={true}
            style={component.style || { left: 40 * index, top: 40 * index, position: 'absolute' }}
          />
        ))
      ) : (
        <DndContext onDragEnd={handleDragEnd} onDragMove={handleDragMove}>
          {components.map((component, index) => (
            <AbsoluteComponentRenderer
              key={component.id}
              id={component.id}
              component={component}
              isSelected={JSON.stringify(selectedPath) === JSON.stringify([index])}
              onClick={() => { console.log('select', [index]); onSelect([index]); }}
              preview={false}
              style={component.style || { left: 40 * index, top: 40 * index, position: 'absolute' }}
            />
          ))}
        </DndContext>
      )}
    </div>
  );
} 